import requests
import pandas as pd
import os
import time
import random
import matplotlib.pyplot as plt
from bs4 import BeautifulSoup
from datetime import datetime
import matplotlib

# 设置中文字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
matplotlib.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

class XinfadiSpider:
    def __init__(self):
        self.base_url = 'http://www.xinfadi.com.cn/priceDetail.html'
        self.api_url = 'http://www.xinfadi.com.cn/getPriceData.html'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
        }
        # 创建数据和分析结果目录
        self.data_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data')
        if not os.path.exists(self.data_dir):
            os.makedirs(self.data_dir)
    
    def get_page_data(self, page=1):
        """
        获取指定页的蔬菜价格数据
        """
        # 使用POST请求获取数据
        data = {
            'current': page,
            'limit': 20,  # 每页显示的数据条数
            'pubDateStartTime': '',  # 可以设置开始日期，格式为'YYYY/MM/DD'
            'pubDateEndTime': '',     # 可以设置结束日期，格式为'YYYY/MM/DD'
            'prodPcatid': '',         # 产品类别ID
            'prodCatid': '',          # 产品子类别ID
            'prodName': ''            # 产品名称
        }
        
        try:
            response = requests.post(self.api_url, headers=self.headers, data=data)
            response.raise_for_status()  # 如果请求不成功则抛出异常
            
            # 解析JSON响应
            json_data = response.json()
            
            if 'list' not in json_data:
                print(f"页面{page}未找到价格数据")
                return []
            
            # 提取数据列表
            items = json_data['list']
            
            # 转换数据格式
            data = []
            for item in items:
                row_data = {
                    'name': item.get('prodName', ''),
                    'low_price': item.get('lowPrice', ''),
                    'price': item.get('avgPrice', ''),
                    'high_price': item.get('highPrice', ''),
                    'spec': item.get('specInfo', ''),
                    'place': item.get('place', ''),
                    'unit': item.get('unitInfo', ''),
                    'pub_date': item.get('pubDate', '')
                }
                data.append(row_data)
            
            print(f"成功获取第{page}页数据，共{len(data)}条")
            return data
        
        except Exception as e:
            print(f"获取第{page}页数据时出错: {e}")
            return []
    
    def _map_field_name(self, header):
        """
        将中文表头映射为英文字段名
        """
        mapping = {
            '品名': 'name',
            '最低价': 'low_price',
            '平均价': 'price',
            '最高价': 'high_price',
            '规格': 'spec',
            '产地': 'place',
            '单位': 'unit',
            '发布日期': 'pub_date'
        }
        return mapping.get(header, header)
    
    def get_multiple_pages_data(self, pages=3):
        """
        获取多页数据
        """
        all_data = []
        
        for page in range(1, pages + 1):
            print(f"正在爬取第{page}页数据...")
            page_data = self.get_page_data(page)
            if page_data:
                all_data.extend(page_data)
            
            # 随机延迟，避免请求过于频繁
            if page < pages:
                delay = random.uniform(1, 3)
                print(f"等待{delay:.2f}秒后继续爬取下一页...")
                time.sleep(delay)
        
        return all_data
    
    def save_to_csv(self, data, filename):
        """
        将数据保存为CSV文件
        """
        if not data:
            print("没有数据可保存")
            return
        
        file_path = os.path.join(self.data_dir, filename)
        df = pd.DataFrame(data)
        
        # 确保目录存在
        os.makedirs(os.path.dirname(file_path), exist_ok=True)
        
        # 保存数据
        df.to_csv(file_path, index=False, encoding='utf-8-sig')
        print(f"数据已保存到 {file_path}")
        
        return file_path
    
    def analyze_vegetable_prices(self, data):
        """
        简单分析蔬菜价格数据
        """
        if not data:
            print("没有数据可分析")
            return
        
        df = pd.DataFrame(data)
        
        # 转换价格列为数值类型
        for col in ['low_price', 'price', 'high_price']:
            if col in df.columns:
                df[col] = pd.to_numeric(df[col], errors='coerce')
        
        # 价格统计分析
        print("\n价格统计分析:")
        price_stats = df.groupby('name')['price'].agg(['mean', 'min', 'max']).reset_index()
        price_stats.columns = ['蔬菜名称', '平均价格', '最低价格', '最高价格']
        print(price_stats.to_string(index=False))
        
        # 按平均价格排序
        print("\n各蔬菜平均价格排序:")
        sorted_by_price = df.groupby('name')['price'].mean().sort_values(ascending=False)
        for name, price in sorted_by_price.items():
            print(f"{name}: {price:.2f}元/{df[df['name']==name]['unit'].iloc[0]}")
        
        # 绘制价格区间图
        self._plot_price_ranges(df)
    
    def _plot_price_ranges(self, df):
        """
        绘制价格区间图
        """
        # 选择前10种蔬菜进行可视化
        top_vegetables = df.groupby('name')['price'].mean().sort_values(ascending=False).head(10).index
        plot_data = df[df['name'].isin(top_vegetables)]
        
        # 创建图表
        plt.figure(figsize=(12, 8))
        
        # 为每种蔬菜绘制价格区间
        for i, name in enumerate(top_vegetables):
            veg_data = plot_data[plot_data['name'] == name]
            if not veg_data.empty:
                plt.errorbar(
                    i, veg_data['price'].mean(),
                    yerr=[[veg_data['price'].mean() - veg_data['low_price'].min()],
                          [veg_data['high_price'].max() - veg_data['price'].mean()]],
                    fmt='o', capsize=5, capthick=2, label=name
                )
        
        plt.xticks(range(len(top_vegetables)), top_vegetables, rotation=45)
        plt.xlabel('蔬菜品种')
        plt.ylabel('价格 (元/单位)')
        plt.title('新发地市场主要蔬菜价格区间')
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.tight_layout()
        
        # 保存图表
        plt.savefig(os.path.join(self.data_dir, 'vegetable_price_ranges.png'))
        print("价格分析图表已保存到", os.path.join(self.data_dir, 'vegetable_price_ranges.png'))
        plt.close()
    
    def run(self, pages=3):
        """
        运行爬虫主流程
        """
        print(f"开始爬取新发地蔬菜价格数据，计划爬取{pages}页...")
        data = self.get_multiple_pages_data(pages)
        if data:
            self.save_to_csv(data, 'vegetable_prices.csv')
            self.analyze_vegetable_prices(data)
            print(f"成功爬取{len(data)}条数据")
        print("爬取完成")